//! 钱包工具
//!

use base64::Engine;
use num_bigint::BigInt;
use std::str::FromStr;

use crate::{
    bean::wallet::{keys::Keys, wallet},
    error::Error,
    mnemonic,
};

/// 获取助记词
pub fn mnemonic(word: &str, random_str: &str) -> Result<mnemonic::Mnemonic, Error> {
    mnemonic::Mnemonic::new(word, random_str)
}

/// 获取钱包
pub fn wallet(word: &str, random_str: &str) -> Result<wallet::Wallet, Error> {
    // 助记词
    let m = mnemonic(word, random_str)?;
    // 主密钥对
    let private_key = m.master_extended_private();
    let public_key = mnemonic::Mnemonic::generate_public_key(&private_key);
    let private_key_str =
        base64::engine::general_purpose::STANDARD.encode(private_key.private_key.secret_bytes());
    let public_key_str = base64::engine::general_purpose::STANDARD.encode(public_key.serialize());
    let keys = Keys::new(&public_key_str, &private_key_str);

    // 扩展秘钥对
    let extend_private = m.get_device_private_key(44, 0, 0, 0, BigInt::from_str("0").unwrap())?;
    let extend_public = mnemonic::Mnemonic::generate_public_key(&extend_private);
    let extend_keys = Keys::new(
        &base64::engine::general_purpose::STANDARD.encode(extend_public.serialize()),
        &base64::engine::general_purpose::STANDARD
            .encode(extend_private.private_key.secret_bytes()),
    );

    // 钱包账户地址
    let address = m.get_address()?;

    // 钱包
    let wallet = wallet::Wallet {
        mnemonic: m.mnemonic().to_string(),
        address,
        keys,
        ext_keys: extend_keys,
    };

    Ok(wallet)
}

pub fn generate_new_address(word: &str, random: &str, index: BigInt) -> Result<String, Error> {
    // 助记词
    let m = mnemonic(word, random)?;
    m.get_new_addeess(0, index)
}

#[cfg(test)]
mod tests {
    use num_bigint::BigInt;

    use crate::bean::wallet::wallet_builder::{generate_new_address, mnemonic, wallet};

    #[test]
    fn test_mnemonic() {
        let m = mnemonic("", "nihao").unwrap();
        println!("{:?}", m);
    }

    #[test]
    fn test_wallet() {
        let wallet = wallet("", "hello").unwrap();
        println!("{:?}", wallet);
    }

    #[test]
    fn test_generate_new_address() {
        let addr = generate_new_address("", "hello", BigInt::from(0)).unwrap();
        println!("addr: {}", addr);
    }
}
